package com.atguigu.gmall.ums.service.impl;

import com.alibaba.nacos.common.utils.MD5Utils;
import com.atguigu.gmall.common.exception.UmsException;
import com.atguigu.gmall.common.utils.RandomUtils;
import com.atguigu.gmall.ums.util.HttpUtils;
import com.atguigu.gmall.ums.util.SMSProperties;
import com.google.gson.Gson;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.common.bean.PageResultVo;
import com.atguigu.gmall.common.bean.PageParamVo;

import com.atguigu.gmall.ums.mapper.UserMapper;
import com.atguigu.gmall.ums.entity.UserEntity;
import com.atguigu.gmall.ums.service.UserService;


@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    private final static String prifix = "usm:code";
    @Autowired
    SMSProperties smsProperties;

    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Override
    public PageResultVo queryPage(PageParamVo paramVo) {
        IPage<UserEntity> page = this.page(
                paramVo.getPage(),
                new QueryWrapper<UserEntity>()
        );

        return new PageResultVo(page);
    }

    @Override
    public Boolean checkData(String data, Integer type) {
        //要校验的数据类型：1，用户名；2，手机；3，邮箱
        QueryWrapper queryWrapper = new QueryWrapper();
        switch (type){
            case 1: queryWrapper.eq("username",data);  break;
            case 2: queryWrapper.eq("phone",data);  break;
            case 3: queryWrapper.eq("email",data);  break;
            default:
                return null;
        }
        return  this.count(queryWrapper) == 0;
    }

    //实现用户注册功能，需要对用户密码进行加密存储，使用MD5加密，
    // 加密过程中使用随机码作为salt加盐。另外还需要对用户输入的短信验证码进行校验。
    @Override
    public void registerUser(UserEntity userEntity, String code) {
        //参数非空验证
        if(userEntity==null|| StringUtils.isBlank(code)){
            throw new UmsException("注册参数不能为空");
        }
        //TODO 使用手机号查询redis中的code，校验短信验证码
        String redis_code = this.redisTemplate.opsForValue().get(prifix + userEntity.getPhone());
        if (StringUtils.isBlank(redis_code)||!StringUtils.equals(redis_code,code)){
            throw new UmsException("注册失败");
        }
        //对密码进行加盐加密
      userEntity.setPassword(DigestUtils.md5Hex(userEntity.getPassword()+code));
        //保存用户
        //为用户的属性设置默认值
        userEntity.setCreateTime(new Date());
        userEntity.setLevelId(1l);
        userEntity.setNickname(userEntity.getUsername());
        userEntity.setGrowth(1000);
        userEntity.setSourceType(1);
        userEntity.setIntegration(1000);
        this.save(userEntity);
        //删除redis中的短信验证码
        this.redisTemplate.delete(prifix+userEntity.getPhone());
    }

    /**
     * 根据参数中的登录名（用户名/手机号/邮箱）和密码查询指定用户
     * @param loginName
     * @param password
     * @return
     */
    @Override
    public UserEntity queryUser(String loginName, String password) {
        //根据用户名查询到指定用户，根据用户返回的盐对传过来的密码进行相同的加密操作然后比较
        UserEntity userEntity = this.getOne(new QueryWrapper<UserEntity>()
                .eq("username", loginName)
                .or().eq("email",loginName)
        .or().eq("phone",loginName));
        if (userEntity==null){
            return userEntity;
        }
        String salt = userEntity.getSalt();
        //对传过来的密码进行加盐
        String md5Hex = DigestUtils.md5Hex(password + salt);
        if (StringUtils.equals(md5Hex,userEntity.getPassword())){
        return userEntity;
        }
        return null;
    }

    //生成短信验证码，并调用短信服务发送短信到手机
    @Override
    public void generateCode(String phone) {
        //生成4位的随机验证码，并保存在redis中
        String fourBitRandom = RandomUtils.getFourBitRandom();
        redisTemplate.opsForValue().set(prifix+phone,fourBitRandom,5, TimeUnit.MINUTES);
        //调用发送手机短信服务
    proxySendMsg(phone,fourBitRandom);
//    this.sendMsgToMQ(phone+"_"+fourBitRandom);
    }
    //实际使用鼎信第三方发送验证码的方法
    public void proxySendMsg(String mobile,String fourBitRandom) {
        String host = smsProperties.getHost();
        String path = smsProperties.getPath();
        String method = smsProperties.getMethod();
        String appcode = smsProperties.getAppCode();
        String tpl_id = smsProperties.getTpl_id();
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("mobile", mobile);
        querys.put("param", "code:"+fourBitRandom);
        querys.put("tpl_id", tpl_id);
        Map<String, String> bodys = new HashMap<String, String>();

        try {
            HttpResponse response = (HttpResponse) HttpUtils.doPost(host, path, method, headers, querys, bodys);
            String responseJson = EntityUtils.toString(response.getEntity(), "UTF-8");
            System.out.println("responseJson = " + responseJson);

            Gson gson = new Gson();
            Map map = gson.fromJson(responseJson, Map.class);
            if (Objects.isNull(map)||!"00000".equals(map.get("return_code"))) {
                throw new RuntimeException(map.get("return_code").toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendMsgToMQ(String phone_code){
        try {
            this.rabbitTemplate
                    .convertAndSend("UMS_CODE_EXCHANGE","CODE",phone_code);
        } catch (AmqpException e) {
//            logger.error("{}商品消息发送异常，商品id：{}", type, id, e);
            e.printStackTrace();
        }
    }
}